<template>
  <div ref="container" class="three-container"></div>
</template>

<script setup>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { onMounted, onUnmounted, ref } from 'vue'

const container = ref()
let scene, camera, renderer, controls, animationId
let roomModel = null
let directionalLight = null
let directionalLightHelper = null
let personCube = null // 代表人的小方块
let moveTarget = null // 移动目标点
let isMoving = false  // 是否正在移动
let moveStartTime = 0 // 移动开始时间
let moveDuration = 2000 // 移动持续时间（毫秒）
let startPosition = new THREE.Vector3() // 起始位置
let targetPosition = new THREE.Vector3() // 目标位置
let isAlarmActive = false // 报警状态
let alarmLight = null // 报警光源
let alarmLightInterval = null // 报警光源闪烁定时器
let personOriginalMaterial = null // 人物原始材质

// 定义事件发射器
const emit = defineEmits(['initialized', 'update'])

// 定义暴露给父组件的方法
defineExpose({
  // 添加模型到场景
  addModel(model) {
    if (scene) {
      scene.add(model)
    }
  },

  // 从场景中移除模型
  removeModel(model) {
    if (scene) {
      scene.remove(model)
    }
  },

  // 更新相机位置
  setCameraPosition(position) {
    if (camera) {
      camera.position.set(position.x, position.y, position.z)
      camera.lookAt(0, 0, 0)
      controls.update()
    }
  },

  // 设置场景背景色
  setBackgroundColor(color) {
    if (scene) {
      scene.background = new THREE.Color(color)
    }
  },

  // 获取场景对象
  getScene() {
    return scene
  },

  // 获取相机对象
  getCamera() {
    return camera
  },

  // 获取渲染器对象
  getRenderer() {
    return renderer
  },

  // 重置相机
  resetCamera() {
    if (camera) {
      camera.position.set(0, 5, 10)
      camera.lookAt(0, 0, 0)
      controls.update()
    }
  },

  // 设置视角
  setView(view) {
    if (!camera) return

    switch(view) {
      case 'top':
        camera.position.set(0, 15, 0)
        camera.lookAt(0, 0, 0)
        camera.up.set(0, 0, -1)
        break
      case 'side':
        camera.position.set(15, 5, 0)
        camera.lookAt(0, 0, 0)
        break
      default:
        camera.position.set(0, 5, 10)
        camera.lookAt(0, 0, 0)
    }

    if (controls) {
      controls.update()
    }
  },

  // 设置方向光位置
  setDirectionalLightPosition(position) {
    if (directionalLight) {
      directionalLight.position.set(position.x, position.y, position.z)
      if (directionalLightHelper) {
        directionalLightHelper.update()
      }
      // 更新光照目标位置
      if (directionalLight.target) {
        directionalLight.target.position.set(0, 0, 0)
      }
    }
  },

  // 设置方向光强度
  setDirectionalLightIntensity(intensity) {
    if (directionalLight) {
      directionalLight.intensity = intensity
    }
  },

  // 切换方向光辅助线显示
  toggleDirectionalLightHelper(visible) {
    if (directionalLightHelper) {
      directionalLightHelper.visible = visible
    }
  },

  // 设置方向光颜色
  setDirectionalLightColor(color) {
    if (directionalLight) {
      directionalLight.color.set(color)
    }
  },
  
  // 移动小方块到指定位置
  movePersonToPosition(x, z) {
    if (!personCube || !scene) return
    
    // 设置目标位置（y轴保持不变，基于当前位置）
    targetPosition.set(x, personCube.position.y, z)
    startPosition.copy(personCube.position)
    
    // 标记为正在移动
    isMoving = true
    moveStartTime = Date.now()
    
    // 存储目标点用于渲染循环中的处理
    moveTarget = targetPosition
  },
  
  // 启动报警
  startAlarm() {
    if (!personCube || !scene) return
    
    // 如果报警已经启动，直接返回
    if (isAlarmActive) return
    
    isAlarmActive = true
    
    // 保存原始材质
    personOriginalMaterial = personCube.material
    
    // 创建更亮的点光源作为报警灯
    alarmLight = new THREE.PointLight(0xff0000, 8, 30)
    alarmLight.position.set(personCube.position.x, personCube.position.y + 2, personCube.position.z)
    alarmLight.castShadow = true
    scene.add(alarmLight)
    
    // 更改人物材质为报警材质（暗红色）
    const alarmMaterial = new THREE.MeshPhongMaterial({ 
      color: 0x8b0000, // 暗红色
      emissive: 0x8b0000,
      emissiveIntensity: 1,
      shininess: 90
    })
    personCube.material = alarmMaterial
    
    // 设置快速闪烁效果 (暗红到亮红)
    let isBright = false
    alarmLightInterval = setInterval(() => {
      if (alarmLight) {
        // 切换亮度
        isBright = !isBright
        alarmLight.intensity = isBright ? 8 : 2
        
        // 同时改变人物材质颜色
        if (personCube.material) {
          personCube.material.color.set(isBright ? 0xff0000 : 0x8b0000)
          personCube.material.emissive.set(isBright ? 0xff0000 : 0x8b0000)
        }
      }
    }, 100) // 每100ms闪烁一次，更快更明显
  },
  
  // 停止报警
  stopAlarm() {
    if (!isAlarmActive) return
    
    isAlarmActive = false
    
    // 清除闪烁定时器
    if (alarmLightInterval) {
      clearInterval(alarmLightInterval)
      alarmLightInterval = null
    }
    
    // 恢复人物原始材质
    if (personCube && personOriginalMaterial) {
      personCube.material = personOriginalMaterial
    }
    
    // 移除报警光源
    if (alarmLight && scene) {
      scene.remove(alarmLight)
      alarmLight = null
    }
  }
})

/**
 * 初始化Three.js场景
 */
function init() {
  // 创建场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xcccccc)

  // 启用阴影贴图
  scene.castShadow = true
  scene.receiveShadow = true

  // 添加雾气效果
  // scene.fog = new THREE.Fog(0xcccccc, 10, 30)

  // 创建相机 - 调整近裁剪面以减少深度冲突
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.5, 1000)
  camera.position.set(0, 5, 10)

  // 创建渲染器 - 启用对数深度缓冲以减少深度冲突
  renderer = new THREE.WebGLRenderer({
    antialias: true,
    logarithmicDepthBuffer: true  // 启用对数深度缓冲
  })
  renderer.setSize(container.value.clientWidth, container.value.clientHeight)
  renderer.setPixelRatio(window.devicePixelRatio)

  // 启用阴影贴图
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFSoftShadowMap

  // 启用物理上正确的光照
  renderer.physicallyCorrectLights = true

  // 将渲染器添加到页面中
  container.value.appendChild(renderer.domElement)

  // 创建控制器
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.05
  controls.screenSpacePanning = false

  // 限制相机距离
  controls.minDistance = 5
  controls.maxDistance = 50

  // 限制平移范围
  controls.panSpeed = 0.5
  controls.minPolarAngle = Math.PI/6 // 限制向上旋转角度
  controls.maxPolarAngle = Math.PI/2 // 限制向下旋转角度

  // 禁用缩放限制（使用距离限制替代）
  controls.enableZoom = true

  // 添加场景内容
  createScene()

  // 发送初始化完成事件
  emit('initialized', { scene, camera, renderer })

  // 开始渲染循环
  animate()

  // 添加窗口大小调整监听
  window.addEventListener('resize', onWindowResize)
}

/**
 * 创建场景
 */
function createScene() {
  // 添加多种光源以更好地照亮场景

  // 环境光 - 提供基础照明，稍微调高一点让阴影区域更亮
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.add(ambientLight)

  // 主方向光 - 模拟太阳光产生阴影
  directionalLight = new THREE.DirectionalLight(0xffffff, 0.7)
  directionalLight.position.set(10, 20, 10)
  directionalLight.castShadow = true

  // 创建光照目标
  const lightTarget = new THREE.Object3D()
  lightTarget.position.set(0, 0, 0)
  scene.add(lightTarget)
  directionalLight.target = lightTarget

  // 设置阴影贴图参数，增加柔和度
  directionalLight.shadow.mapSize.width = 2048
  directionalLight.shadow.mapSize.height = 2048
  directionalLight.shadow.camera.near = 0.5
  directionalLight.shadow.camera.far = 50
  directionalLight.shadow.camera.left = -20
  directionalLight.shadow.camera.right = 20
  directionalLight.shadow.camera.top = 20
  directionalLight.shadow.camera.bottom = -20

  // 增加阴影的柔和度
  directionalLight.shadow.radius = 4

  scene.add(directionalLight)

  // 添加方向光辅助线（默认隐藏）
  directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5)
  directionalLightHelper.visible = false
  scene.add(directionalLightHelper)

  // 补充方向光 - 填充阴影，减少对比度
  const fillLight = new THREE.DirectionalLight(0xffffff, 0.4)
  fillLight.position.set(-10, 10, -10)
  scene.add(fillLight)

  // 背光 - 增加深度感
  const backLight = new THREE.DirectionalLight(0xffffff, 0.3)
  backLight.position.set(0, 10, -20)
  scene.add(backLight)

  // 半球光 - 模拟天空和地面的光线反射
  const hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 0.3)
  scene.add(hemiLight)

  // 创建代表人的小方块
  createPersonCube()

  // 加载room.glb模型
  loadRoomModel()
}

/**
 * 创建代表人的小方块
 */
function createPersonCube() {
  const geometry = new THREE.BoxGeometry(0.5, 1, 0.5)
  // 默认使用蓝色材质
  const material = new THREE.MeshPhongMaterial({ 
    color: 0x0000ff, // 蓝色
    shininess: 30 
  })
  personCube = new THREE.Mesh(geometry, material)
  
  // 启用阴影
  personCube.castShadow = true
  personCube.receiveShadow = true
  
  // 放置在场景中心稍高的位置
  personCube.position.set(0, 0.5, 0)
  
  scene.add(personCube)
}

/**
 * 加载room.glb模型
 */
function loadRoomModel() {
  // 设置DRACO解压器
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('/libs/draco/gltf/')

  // 创建GLTF加载器
  const loader = new GLTFLoader()
  loader.setDRACOLoader(dracoLoader)

  // 加载模型
  loader.load('/model/room.glb', (gltf) => {
    roomModel = gltf.scene

    // 确保模型能够接收阴影
    roomModel.traverse((child) => {
      if (child.isMesh) {
        child.castShadow = true
        child.receiveShadow = true
      }
    })

    // 将模型放置在场景中心
    roomModel.position.set(0, 0, 0)

    // 将模型添加到场景中
    scene.add(roomModel)

    // 调整相机位置以适应模型
    const box = new THREE.Box3().setFromObject(roomModel)
    const center = box.getCenter(new THREE.Vector3())
    const size = box.getSize(new THREE.Vector3()).length()

    // 调整相机位置以更好地查看模型
    camera.position.set(center.x, center.y + size, center.z + size)
    camera.lookAt(center)
    controls.update()
  }, undefined, (error) => {
    console.error('加载模型时出错:', error)
  })
}

/**
 * 渲染动画循环
 */
function animate() {
  animationId = requestAnimationFrame(animate)

  // 处理人物移动逻辑
  if (isMoving && moveTarget) {
    const elapsed = Date.now() - moveStartTime
    const progress = Math.min(elapsed / moveDuration, 1.0)
    
    // 使用缓动函数使移动更加自然
    const easeProgress = 1 - Math.pow(1 - progress, 3)
    
    // 插值计算当前位置
    personCube.position.lerpVectors(startPosition, targetPosition, easeProgress)
    
    // 计算移动方向向量
    const moveDirection = new THREE.Vector3().subVectors(targetPosition, startPosition)
    
    // 计算旋转角度（绕X轴旋转，模拟滚动效果）
    const distance = moveDirection.length()
    if (distance > 0) {
      // 根据移动进度计算旋转角度
      const rotationAngle = easeProgress * (distance / 0.5) * Math.PI * 2
      personCube.rotation.x = rotationAngle
    }
    
    // 如果已到达目标位置
    if (progress >= 1.0) {
      isMoving = false
      moveTarget = null
      // 停止旋转
      personCube.rotation.x = 0
    }
  }
  
  // 更新报警光源位置以跟随人物
  if (isAlarmActive && alarmLight && personCube) {
    alarmLight.position.set(personCube.position.x, personCube.position.y + 1, personCube.position.z)
  }

  // 更新控制器
  if (controls) {
    controls.update()
  }

  renderer.render(scene, camera)

  // 发送更新事件
  emit('update', { scene, camera, renderer })
}

/**
 * 窗口大小调整处理
 */
function onWindowResize() {
  camera.aspect = container.value.clientWidth / container.value.clientHeight
  camera.updateProjectionMatrix()
  renderer.setSize(container.value.clientWidth, container.value.clientHeight)
}

/**
 * 清理资源
 */
function cleanup() {
  if (animationId) {
    cancelAnimationFrame(animationId)
  }

  // 清除报警定时器
  if (alarmLightInterval) {
    clearInterval(alarmLightInterval)
  }

  if (renderer) {
    renderer.dispose()
  }

  // 移除事件监听器
  window.removeEventListener('resize', onWindowResize)
}

// 组件挂载时初始化
onMounted(() => {
  init()
})

// 组件卸载时清理资源
onUnmounted(() => {
  cleanup()
})
</script>

<style scoped>
.three-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>